package com.accesshollywood.components;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultCellEditor;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.TableCellRenderer;

import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;

import com.accesshollywood.SQL.GFXSQL;
import com.accesshollywood.SQL.IndexedSQL;
import com.accesshollywood.clipboard.ClipboardUtil;
import com.accesshollywood.components.BasicPopupMenu.POPUP_ITEMS;
import com.accesshollywood.grfxOrdering.GRFXOrdersMain;
import com.accesshollywood.grfxOrdering.OrderMainGUI;
import com.accesshollywood.grfxOrdering.panels.DragNDropPanel;
import com.accesshollywood.models.EditableOneColumnTableModel;
import com.accesshollywood.speech.Speak;

public class EditableOneColumnTable{// extends JTable implements HasPopupMenu {
/*
	private boolean						editable		= false;
	private static IndexedSQL			oldEntry		= null;
	private EditableOneColumnTableModel	model;
	protected JComponent				parent;
	protected Class						refreshMe		= OrderMainGUI.class;
	public BasicPopupMenu				popup			= new BasicPopupMenu(this);
	private boolean						singleLine		= true;

	public EditableOneColumnTable(JComponent parent, String tableName, String columnName, String idName, int fontSize, boolean singleLine) {
		super();
		this.parent = parent;
		this.singleLine = singleLine;
		model = new EditableOneColumnTableModel(tableName, columnName, idName);
		setModel(model);
		setup(fontSize);
	}

	public EditableOneColumnTable(JComponent parent, String tableName, String columnName, String idName, String listTableName, String listColumnName, String listIdName, String listExtraData, int listID, int fontSize, boolean singleLine) {
		super();
		this.parent = parent;
		this.singleLine = singleLine;
		model = new EditableOneColumnTableModel(tableName, columnName, idName, listTableName, listColumnName, listIdName, listExtraData, listID);
		setModel(model);
		setup(fontSize);
	}

	public EditableOneColumnTable(JComponent parent, EditableOneColumnTableModel model, int fontSize, boolean singleLine) {
		super();
		this.parent = parent;
		this.singleLine = singleLine;
		this.model = model;
		setModel(model);
		setup(fontSize);
	}

	public void setModel(EditableOneColumnTableModel model) {
		super.setModel(model);
		this.model = model;
	}

	public EditableOneColumnTableModel getModel() {
		return model;
	}

	public void setup(int fontSize) {
		setTableHeader(null);
		setFont(new Font(this.getFont().getName(), this.getFont().getStyle(), fontSize));
		setFillsViewportHeight(true);
		putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
		setShowGrid(false);
		setShowHorizontalLines(true);
		setShowVerticalLines(false);
		setColumnSelectionAllowed(true);
		setRowSelectionAllowed(true);
		setRowHeight(fontSize + 6);

		if (singleLine) {
			setDefaultEditor(Object.class, new SingleLineTableEditor());
		} else {
			setDefaultRenderer(Object.class, new MultiLineTableRenderer());
			setDefaultEditor(Object.class, new MultiLineTableEditor());
		}

		setOpaque(false);
	}

	public void setupPopup() {
		if (popup.popupItems.contains(POPUP_ITEMS.ADD)) {
			popup.addMenuItem("Add", new AddActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.EDIT)) {
			popup.addMenuItem("Edit", new EditActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.COPY)) {
			popup.addMenuItem("Copy", new CopyActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.DELETE)) {
			popup.addMenuItem("Delete", new DeleteActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.READ_ALOUD)) {
			popup.addMenuItem("Read Aloud", new ReadAloudActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.SPELL_ALOUD)) {
			popup.addMenuItem("Spell Aloud", new SpellAloudActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.OPEN_FOLDER)) {
			popup.addMenuItem("Open Folder", new OpenFolderActionListener());
		}
		if (popup.popupItems.contains(POPUP_ITEMS.CLEAR_FOLDER)) {
			popup.addMenuItem("Clear Folder", new ClearFolderActionListener());
		}
	}

	public boolean isCellEditable(int rowIndex, int cellIndex) {
		return editable;
	}

	public void changeSelection(int row, int column, boolean toggle, boolean extend) {
		super.changeSelection(row, column, toggle, extend);
		if (editCellAt(row, column)) {
			Component editor = getEditorComponent();
			editor.requestFocusInWindow();
		}
	}

	public class EditableFocusListener implements FocusListener {

		@Override
		public void focusGained(FocusEvent fe) {
		}

		@Override
		public void focusLost(FocusEvent fe) {
			if (editable) {
				int row = getSelectedRow();
				int col = 0;
				if (row > -1) {
					editable = true;
					IndexedSQL newEntry;
					Object whatsHere = getValueAt(row, col);
					if ((whatsHere instanceof String)) {
						int oldEntryID = oldEntry.getID();
						newEntry = new IndexedSQL(oldEntryID, (String) whatsHere);
					} else {
						newEntry = (IndexedSQL) whatsHere;
					}

					if (oldEntry == null || (oldEntry != null && !oldEntry.equals(newEntry))) {
						Integer[] id;

						GFXSQL.alterString(model.sqlTableName, model.sqlEntryColumnName, newEntry.toString(), newEntry.getID());
						GRFXOrdersMain.refresh("items", new int[] { oldEntry.getID() }, true);

						model.p2pRefreshEntry(oldEntry.getID());
					}
					editable = false;
				}
			}
		}

	}

	public class AddActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;
			Object whatsHere = getValueAt(row, col);
			IndexedSQL newEntry = null;
			if (singleLine) {
				int id = GFXSQL.addString(model.sqlTableName, model.sqlEntryColumnName, "new item...");
				newEntry = new IndexedSQL(id, "new item...");
				if (!model.isDirectList) {
					String[] columns = { model.sqlListIdColumnName, model.sqlIdColumnName };
					Integer[] data = { model.listID, id };
					int id2 = GFXSQL.addInts(model.sqlListTableName, columns, data);
					model.p2pRefreshList(id2);
					// Trace.info(id2);
				}
			}
			refresh(true);
			beginEdit(newEntry);
		}
	}

	public class EditActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;
			beginEdit(row, col);
		}
	}

	public int getRowOfEntry(IndexedSQL entry) {
		for (int i = 0; i < model.getRowCount(); i++) {
			IndexedSQL currEntry = (IndexedSQL) model.getValueAt(i, 0);
			if (entry.equals(currEntry.toString())) {
				return i;
			}
		}
		return -1;
	}

	public void beginEdit(IndexedSQL entry) {
		int row = getRowOfEntry(entry);
		if (row != -1) {
			beginEdit(row, 0);
		}
	}

	@SuppressWarnings("unchecked")
	public void beginEdit(int row, int col) {
		if (row > -1) {
			editable = true;
			oldEntry = (IndexedSQL<String>) getValueAt(row, col);
			boolean success = editCellAt(row, col);
			if (success) {
				boolean toggle = false;
				boolean extend = false;
				changeSelection(row, col, toggle, extend);
			}
		}
	}

	public class CopyActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;
			IndexedSQL<String> entry = (IndexedSQL<String>) getValueAt(row, col);
			ClipboardUtil.copyText(entry.getElement());
		}
	}

	public class DeleteActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;
			if (row != -1) {
				model = (EditableOneColumnTableModel) EditableOneColumnTable.this.getModel();

				int id = ((IndexedSQL) getValueAt(row, col)).getID();

				GFXSQL.removeElement(model.sqlTableName, model.sqlIdColumnName + "=" + id);
				if (!model.isDirectList) {
					GFXSQL.removeElement(model.sqlListTableName, model.sqlIdColumnName + "=" + id);
					model.p2pRefreshEntry(id);
				}
			}
			refresh(true);
		}

	}

	public class ReadAloudActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;
			Object a = getValueAt(row, col);

			IndexedSQL readme = (IndexedSQL) getValueAt(row, col);
			// Trace.info("reading...   " + readme.toString());
			Speak.say(readme.toString());
		}

	}

	public class SpellAloudActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;

			IndexedSQL readme = (IndexedSQL) getValueAt(row, col);
			// Trace.info("spelling...   " + readme.toString());
			Speak.spell(readme.toString());
		}

	}

	public class OpenFolderActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;

			if (model instanceof EditableOneColumnTableModel) {
				if (model.getExtraData() != "") {
					File f = new File(model.getExtraData());

					if (f.exists()) {
						Runtime r = Runtime.getRuntime();
						try {
							r.exec("explorer.exe \"" + f.getAbsolutePath() + "\"");
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					} else {
						JOptionPane.showMessageDialog(null, "WARNING!\nFOLDER   " + f.getAbsolutePath() + "   NOT FOUND.", "ERROR", JOptionPane.ERROR_MESSAGE);
					}
				} else {
					JOptionPane.showMessageDialog(null, "WARNING!  NO FOLDER SET.", "ERROR", JOptionPane.ERROR_MESSAGE);
				}
			}
		}
	}

	public class ClearFolderActionListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			int col = 0;

			if (model instanceof EditableOneColumnTableModel) {
				model.setExtraData("");
				((DragNDropPanel) parent).setLink(model.getExtraData());
				((DragNDropPanel) parent).refreshTitle();
			}
		}
	}

	public synchronized Class getRefreshMe() {
		return refreshMe;
	}

	public synchronized void setRefreshMe(Class refreshMe) {
		this.refreshMe = refreshMe;
	}

	public void refresh(boolean fromSQL) {
		try {
			Method refreshMethod = refreshMe.getDeclaredMethod("refresh", boolean.class);
			refreshMethod.invoke(refreshMe, fromSQL);
		} catch (Exception e) {
			e.printStackTrace();
		}
		// , refresh(fromSQL);
		System.out.println(parent);
	}

	private class SingleLineTableEditor extends DefaultCellEditor {

		public SingleLineTableEditor() {
			super(new JTextField());
			final JTextField tf = new JTextField();

			addCellEditorListener(new CellEditorListener() {

				@Override
				public void editingCanceled(ChangeEvent arg0) {
				}

				@Override
				public void editingStopped(ChangeEvent arg0) {
					SingleLineTableEditor editor = (SingleLineTableEditor) arg0.getSource();
					JTextField textField = (JTextField) editor.getComponent();

					AutoCompleteDecorator.decorate(textField, GRFXOrdersMain.preApprovedDictionary.toWordList(), false);
					
					IndexedSQL arg = oldEntry;
					IndexedSQL<String> newEntry = new IndexedSQL(oldEntry.getID(), textField.getText());
					
					if (!oldEntry.getElement().equals(newEntry.getElement())) {
						GFXSQL.alterString(model.sqlTableName, model.sqlEntryColumnName, newEntry.toString(), newEntry.getID());
						GRFXOrdersMain.refresh(model.sqlEntryColumnName, new int[] { newEntry.getID() }, true);
						model.p2pRefreshEntry(newEntry.getID());
					}
				}

			});
		}
	}

	private class MultiLineTableEditor extends DefaultCellEditor {
		public MultiLineTableEditor() {
			super(new JTextField());
			final JTextArea textArea = new JTextArea();
			textArea.setWrapStyleWord(true);
			textArea.setLineWrap(true);
			if (oldEntry != null) {
				textArea.setRows(oldEntry.toString().split("\n").length + 2);
			} else {
				textArea.setRows(2);
			}
			JScrollPane scrollPane = new JScrollPane(textArea);
			scrollPane.setPreferredSize(new Dimension(textArea.getWidth(), textArea.getHeight() * 2));
			scrollPane.setMinimumSize(new Dimension(textArea.getWidth(), textArea.getHeight() * 2));
			scrollPane.setMaximumSize(new Dimension(textArea.getWidth(), textArea.getHeight() * 2));
			scrollPane.setBorder(null);
			editorComponent = scrollPane;
			addCellEditorListener(new CellEditorListener() {

				@Override
				public void editingCanceled(ChangeEvent arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void editingStopped(ChangeEvent arg0) {
					IndexedSQL<String> newEntry = new IndexedSQL(oldEntry.getID(), textArea.getText());
					if (!oldEntry.getElement().equals(newEntry.getElement())) {
						GFXSQL.alterString(model.sqlTableName, model.sqlEntryColumnName, newEntry.toString(), newEntry.getID());
						GRFXOrdersMain.refresh("items", new int[] { newEntry.getID() }, true);
						model.p2pRefreshEntry(newEntry.getID());
					}
				}

			});

			delegate = new DefaultCellEditor.EditorDelegate() {
				public void setValue(Object value) {
					textArea.setText((value != null) ? value.toString() : "");
				}

				public Object getCellEditorValue() {
					return textArea.getText();
				}
			};
		}
	}

	private class MultiLineTableRenderer extends JTextArea implements TableCellRenderer {
		private List<List<Integer>>	rowColHeight	= new ArrayList<List<Integer>>();

		public MultiLineTableRenderer() {
			// Trace.info("hi");
			setLineWrap(true);
			setWrapStyleWord(true);
			// setOpaque(true);
		}

		public Component getTableCellRendererComponent(
				JTable table, Object value, boolean isSelected, boolean hasFocus,
				int row, int column) {
			if (isSelected) {
				setForeground(table.getSelectionForeground());
				setBackground(table.getSelectionBackground());
			} else {
				setForeground(table.getForeground());
				setBackground(table.getBackground());
			}
			setFont(table.getFont());
			if (hasFocus) {
				setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
				if (table.isCellEditable(row, column)) {
					setForeground(UIManager.getColor("Table.focusCellForeground"));
					setBackground(UIManager.getColor("Table.focusCellBackground"));
				}
			} else {
				setBorder(new EmptyBorder(1, 2, 1, 2));
			}
			if (value != null) {
				setText(value.toString());
			} else {
				setText("");
			}
			adjustRowHeight(table, row, column);
			return this;
		}

		private void adjustRowHeight(JTable table, int row, int column) {
			// The trick to get this to work properly is to set the width of the column to the
			// textarea. The reason for this is that getPreferredSize(), without a width tries
			// to place all the text in one line. By setting the size with the with of the column,
			// getPreferredSize() returnes the proper height which the row should have in
			// order to make room for the text.
			int cWidth = 300;// table.getTableHeader().getColumnModel().getColumn(column).getWidth();
			setSize(new Dimension(cWidth, 1000));
			int prefH = getPreferredSize().height;
			while (rowColHeight.size() <= row) {
				rowColHeight.add(new ArrayList<Integer>(column));
			}
			List<Integer> colHeights = rowColHeight.get(row);
			while (colHeights.size() <= column) {
				colHeights.add(0);
			}
			colHeights.set(column, prefH);
			int maxH = prefH;
			for (Integer colHeight : colHeights) {
				if (colHeight > maxH) {
					maxH = colHeight;
				}
			}
			if (table.getRowHeight(row) != maxH) {
				table.setRowHeight(row, maxH);
			}
		}
	}
	*/
}
